import {
  BadRequestException,
  ConflictException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';

import { PrismaService } from '@/modules/prisma/prisma.service';

import { LoginParamsDto } from './auth.dto';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject } from '@nestjs/common';
import { Cache } from 'cache-manager';
import * as svgCaptcha from 'svg-captcha';
import { v4 as uuid } from 'uuid';

@Injectable()
export class AuthService {
  constructor(
    private prisma: PrismaService,
    private readonly jwtService: JwtService,
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
  ) {}

  async getCaptcha() {
    const captcha = svgCaptcha.createMathExpr({
      size: 4, // 验证码长度
      ignoreChars: '0oO1ilI', // 验证码字符中排除 0oO1ilI
      noise: 2, // 干扰线条的数量
      width: 132,
      height: 40,
      fontSize: 50,
      color: true, // 验证码的字符是否有颜色，默认没有，如果设定了背景，则默认有
      background: '#fff',
    });
    // 存储到Redis (key: timestamp, 有效期1分钟)
    const key = `captcha:${Date.now()}`;
    console.log(captcha.text);
    await this.cacheManager.set(key, captcha.text, 60000); //60秒

    return {
      key, // 返回key给前端，验证时需要提交
      svg: captcha.data,
    };
  }

  async register(params: LoginParamsDto) {
    const { phone, password, captchaCode, captchaKey } = params;
    //核实验证码
    const storedCaptcha = await this.cacheManager.get(captchaKey);
    if (!storedCaptcha || storedCaptcha !== captchaCode) {
      throw new BadRequestException('验证码错误或已过期');
    }
    const existUser = await this.prisma.user.findFirst({
      where: { phone: phone },
    });
    //手机号是否已被注册
    if (existUser) {
      throw new ConflictException('手机号已被注册');
    }
    //密码加密存到数据库
    const salt = await bcrypt.genSalt();
    const hashedPassword = await bcrypt.hash(password, salt);
    //默认用户名
    const defaultUsername = `User_${phone.slice(-4)}`;
    const defaultAvatar = '待定';
    const fileId = uuid();

    const user = await this.prisma.user.create({
      data: {
        phone: phone,
        password: hashedPassword,
        username: defaultUsername,
        avatar: defaultAvatar,
      },
    });
    await this.prisma.friend.create({
      data: {
        userId: user.userId,
        friendId: user.userId,
        remark: user.username,
      },
    });
    await this.prisma.file.create({
      data: {
        id: fileId,
        name: '云文档',
        type: 'folder',
        status: 'active',
        creatId: user.userId,
      },
    });

    await this.cacheManager.del(captchaKey);
    return '注册成功';
  }

  async login(params: LoginParamsDto) {
    const { phone, password, captchaCode, captchaKey } = params;
    //核实验证码
    const storedCaptcha = await this.cacheManager.get(captchaKey);
    if (!storedCaptcha || storedCaptcha !== captchaCode) {
      throw new BadRequestException('验证码错误或已过期');
    }
    //获取并验证密码
    // 验证用户是否存在
    const user = await this.prisma.user.findFirst({
      where: { phone: phone },
    });
    if (!user) {
      throw new BadRequestException('用户未注册');
    }
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      throw new BadRequestException('密码错误');
    }
    const updateStatus = await this.prisma.user.update({
      where: { userId: user.userId },
      data: { status: 'active' },
      select: {
        userId: true,
        phone: true,
        username: true,
        status: true,
        avatar: true,
      },
    });
    // 生成JWT令牌
    const payload = {
      sub: user.userId,
      phone: user.phone,
      username: user.username,
    };
    const access_token = this.jwtService.sign(payload, { expiresIn: '1d' });

    return {
      access_token,
      user: updateStatus,
    };
  }

  async getUserInfo(id: number) {
    const user = await this.prisma.user.findFirst({
      where: { userId: id },
      select: {
        userId: true,
        phone: true,
        username: true,
        status: true,
        avatar: true,
      },
    });
    return user;
  }
}
